package com.drakulo.games.ais.core.building;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import com.drakulo.games.ais.core.Colony;
import com.drakulo.games.ais.core.Resource;
import com.drakulo.games.ais.core.delayed.BuildingAction;
import com.drakulo.games.ais.core.delayed.DelayedAction;
import com.drakulo.games.ais.core.delayed.PreparationAction;
import com.drakulo.games.ais.core.io.BuildingIO;

/**
 * Helper for building management
 * 
 * @author Drakulo
 * 
 */
public final class BuildingHelper {
	/**
	 * Private constructor
	 */
	private BuildingHelper() {
		// Nothing there
	}

	/**
	 * Creates a lvl 1 building of the given type
	 * 
	 * @param type
	 *            the building type
	 * @return the created building
	 */
	public static Building create(BuildingType type) {
		return create(type, 1);
	}

	/**
	 * Creates a building of the given type at the given level
	 * 
	 * @param type
	 *            the building type
	 * @return
	 */
	public static Building create(BuildingType type, int level) {
		Building b = new Building(type);
		b.setLevel(level);
		return b;
	}

	/**
	 * Create a upgraded building from the source.
	 * 
	 * @param b
	 *            the building source
	 * @return a +1 level building
	 */
	public static Building upgradeBuilding(Building b) {
		Building updated = b.clone();
		updated.setLevel(b.getLevel() + 1);
		return updated;
	}

	public static Map<Resource, BigDecimal> getProductionOf(Building b) {
		BuildingData data = BuildingIO.getBuildingData(b.getType());
		return data.getLevelData(b.getLevel()).getProduction();
	}

	public static Map<Resource, BigDecimal> getConsumptionOf(Building b) {
		BuildingData data = BuildingIO.getBuildingData(b.getType());
		return data.getLevelData(b.getLevel()).getConsumption();
	}

	public static Map<Resource, BigDecimal> getStoreSpaceOf(Building b) {
		BuildingData data = BuildingIO.getBuildingData(b.getType());
		return data.getLevelData(b.getLevel()).getStoreCapacity();
	}

	public static Map<Resource, BigDecimal> getUpgradeCostOf(Building b) {
		BuildingData data = BuildingIO.getBuildingData(b.getType());
		return data.getLevelData(b.getLevel()).getUpgradeCost();
	}

	public static void copyMap(Map<Resource, BigDecimal> source,
			Map<Resource, BigDecimal> dest) {
		Resource[] resources = Resource.values();
		for (Resource r : resources) {
			dest.put(r, source.get(r));
		}
	}

	public static BuildingAction createAction(Colony c, BuildingType t,
			Map<Resource, BigDecimal> cost) {
		Building b = BuildingHelper.create(t);
		b.setUnderConstruction(true);
		final int duration = 5; // TODO externalize this
		final int robots = 1; // TODO externalize this

		BuildingAction ba = new BuildingAction(c, cost, b, duration, robots);
		return ba;
	}

	public static PreparationAction create(Colony c) {
		Map<Resource, BigDecimal> costMap = new HashMap<Resource, BigDecimal>();
		// TODO externalize cost
		costMap.put(Resource.ENERGY, BigDecimal.valueOf(25));
		PreparationAction pa = new PreparationAction(c, costMap, 5);
		return pa;
	}

	public static void createCMConstructionCallback(int x, int y, final Colony c) {
		// Ground preparation
		PreparationAction pa00 = createCleaningAction(c, x - 1, y - 1);
		PreparationAction pa10 = createCleaningAction(c, x, y - 1);
		PreparationAction pa20 = createCleaningAction(c, x + 1, y - 1);
		PreparationAction pa01 = createCleaningAction(c, x - 1, y);
		PreparationAction pa21 = createCleaningAction(c, x + 1, y);
		PreparationAction pa02 = createCleaningAction(c, x - 1, y + 1);
		PreparationAction pa12 = createCleaningAction(c, x, y + 1);
		PreparationAction pa22 = createCleaningAction(c, x + 1, y + 1);

		// Road construction
		BuildingAction n = createBuildingAction(c, x, y - 1, BuildingType.ROAD);
		BuildingAction e = createBuildingAction(c, x + 1, y, BuildingType.ROAD);
		BuildingAction w = createBuildingAction(c, x - 1, y, BuildingType.ROAD);
		BuildingAction s = createBuildingAction(c, x, y + 1, BuildingType.ROAD);

		// Buildings construction
		BuildingAction nw = createBuildingAction(c, x - 1, y - 1,
				BuildingType.SOLAR_PLANT);
		BuildingAction ne = createBuildingAction(c, x + 1, y - 1,
				BuildingType.GAS_REFINERY);
		BuildingAction sw = createBuildingAction(c, x - 1, y + 1,
				BuildingType.CRISTAL_MINE);
		BuildingAction se = createBuildingAction(c, x + 1, y + 1,
				BuildingType.BIO_FARM);
		se.setCallback(new Runnable() {

			@Override
			public void run() {
				c.setCommandCenterBuilt(true);
			}
		});

		// Now create the chain
		link(c, pa20, pa01, pa21, pa02);
		link(c, pa02, pa12, pa22, n);
		link(c, n, e, w, s);
		link(c, s, nw, ne, sw);
		link(c, sw, se);

		c.addPreparationAction(pa00);
		c.addPreparationAction(pa10);
		c.addPreparationAction(pa20);
	}

	private static PreparationAction createCleaningAction(Colony c, int x, int y) {
		PreparationAction pa = new PreparationAction(c, null, 5);
		pa.setX(x);
		pa.setY(y);
		return pa;
	}

	private static BuildingAction createBuildingAction(Colony c, int x, int y,
			BuildingType type) {
		return new BuildingAction(c, null, new Building(type, x, y), 5, 1);
	}

	private static void link(final Colony c, DelayedAction parent,
			final DelayedAction... children) {
		parent.setCallback(new Runnable() {

			@Override
			public void run() {
				for (DelayedAction da : children) {
					if (da instanceof PreparationAction) {
						PreparationAction pa = (PreparationAction) da;
						c.addPreparationAction(pa);
					} else if (da instanceof BuildingAction) {
						BuildingAction ba = (BuildingAction) da;
						c.addBuildingAction(ba);

					}
				}
			}
		});
	}
}
